﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace Nave.Tecnique
{
    /// <summary>
    /// Renderer合并工具类
    /// </summary>
    public static class RendererCombiner
    {

        /// <summary>
        /// 合并多个SkinnedMeshRenderer
        /// 注意：支持支单个material
        /// </summary>
        public static void Merge(SkinnedMeshRenderer[] skinneds)
        {
            if (skinneds == null || skinneds.Length == 0) return;

            //遍历记录需要合并的meshes、textures、uv、material、bones
            Material sharedMaterial = null;
            var combines = new List<CombineInstance>();
            List<Vector2[]> uvs = new List<Vector2[]>();
            int numOfUv = 0;
            List<Texture2D> textures = new List<Texture2D>();
            List<Transform> bones = new List<Transform>();
            SkinnedMeshRenderer combinedSkin = null;

            using (Timewatch tw = new Timewatch(" Merge Skins - Collect Infos "))
            {
                for (int i = 0; i < skinneds.Length; i++)
                {
                    SkinnedMeshRenderer skinned = skinneds[i];
                    if (sharedMaterial == null)
                        sharedMaterial = GameObject.Instantiate(skinned.sharedMaterial);

                    int subMeshCount = skinned.sharedMesh.subMeshCount;
                    for (int sub = 0; sub < subMeshCount; sub++)
                    {
                        var cbi = new CombineInstance();
                        cbi.mesh = skinned.sharedMesh;
                        cbi.subMeshIndex = sub;
                        combines.Add(cbi);
                    }

                    uvs.Add(skinned.sharedMesh.uv);
                    numOfUv += skinned.sharedMesh.uv.Length;
                    textures.Add(skinned.sharedMaterial.mainTexture as Texture2D);
                    bones.AddRange(skinned.bones);

                    if (combinedSkin == null) combinedSkin = skinned;
                    else GameObject.Destroy(skinned.gameObject);
                }
            }

            //合并使用了的纹理资源
            Rect[] rects = null;
            using (Timewatch tw = new Timewatch(" Create Atlas "))
            {
                sharedMaterial.mainTexture = AtlasCreator.CreateAtlas(textures.ToArray(), 1024, out rects);
            }

            //重新展网格的UV信息
            Vector2[] atlasUVs = new Vector2[numOfUv];
            int j = 0;
            for (int i = 0; i < uvs.Count; i++)
            {
                foreach (Vector2 uv in uvs[i])
                {
                    atlasUVs[j].x = Mathf.Lerp(rects[i].xMin, rects[i].xMax, uv.x);
                    atlasUVs[j].y = Mathf.Lerp(rects[i].yMin, rects[i].yMax, uv.y);
                    j++;
                }
            }

            using (Timewatch tw = new Timewatch(" Merge Skins - CombineMeshes "))
            {
                //合并mesh 构建一个新的SkinnedMeshRenderer
                combinedSkin.name = "Combined_Skinn";
                combinedSkin.sharedMesh = new Mesh();
                combinedSkin.sharedMesh.CombineMeshes(combines.ToArray(), true, false);
                combinedSkin.bones = bones.ToArray();
                combinedSkin.sharedMesh.uv = atlasUVs;
                combinedSkin.material = sharedMaterial;
            }
        }









    }
}
